﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using DHJ.Cost.Models.Dto;
using Microsoft.EntityFrameworkCore;

namespace DHJ.Cost.Models
{
    public class ModelAppService : CostAppServiceBase, IModelAppService
    {
        private readonly IRepository<Launch> _launchRepository;
        private readonly IRepository<Model> _modelRepository;

        public ModelAppService(IRepository<Model> modelRepository, IRepository<Launch> launchRepository)
        {
            _modelRepository = modelRepository;
            _launchRepository = launchRepository;
        }

        #region 型号相关

        public async Task<PagedResultDto<ModelListDto>> GetModels(GetModelsInput input)
        {
            var query = _modelRepository.GetAll()
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(),
                    m => m.Code.Contains(input.Filter) ||
                         m.Name.Contains(input.Filter) ||
                         m.Description.Contains(input.Filter));

            var count = await query.CountAsync();
            var models = await query.OrderBy(input.Sorting)
                .PageBy(input)
                .ToListAsync();

            return new PagedResultDto<ModelListDto>(count, ObjectMapper.Map<List<ModelListDto>>(models));
        }

        public async Task<ListResultDto<ComboboxItemDto>> GetComboboxModels()
        {
            return new ListResultDto<ComboboxItemDto>(
                await _modelRepository.GetAll()
                    .Select(e => new ComboboxItemDto(e.Id.ToString(), e.Code)).ToListAsync());
        }

        public async Task<GetModelForEditOutput> GetModelForEdit(NullableIdDto input)
        {
            ModelEditDto modelEditDto;

            if (input.Id.HasValue)
            {
                var model = await _modelRepository.GetAsync(input.Id.Value);
                modelEditDto = ObjectMapper.Map<ModelEditDto>(model);
            }
            else
            {
                modelEditDto = new ModelEditDto();
            }

            return new GetModelForEditOutput
            {
                Model = modelEditDto
            };
        }

        public async Task CreateOrUpdateModel(ModelEditDto input)
        {
            if (input.Id.HasValue)
                await UpdateModelAsync(input);
            else
                await CreateModelAsync(input);
        }

        public async Task DeleteModel(EntityDto input)
        {
            await _modelRepository.DeleteAsync(input.Id);
        }

        private async Task CreateModelAsync(ModelEditDto input)
        {
            var model = new Model(input.Code, input.Name, input.Description);
            await _modelRepository.InsertAsync(model);
        }

        private async Task UpdateModelAsync(ModelEditDto input)
        {
            Debug.Assert(input.Id != null, "input.Id != null");
            var model = await _modelRepository.GetAsync(input.Id.Value);
            ObjectMapper.Map(input, model);
            await _modelRepository.UpdateAsync(model);
        }

        #endregion

        #region 发次相关

        public async Task<PagedResultDto<LaunchListDto>> GetLaunches(GetLaunchesInput input)
        {
            var query = _launchRepository.GetAll()
                .WhereIf(input.ModelId.HasValue, l => l.ModelId == input.ModelId);

            var count = await query.CountAsync();
            var launches = await query.OrderBy(input.Sorting)
                .PageBy(input)
                .ToListAsync();

            return new PagedResultDto<LaunchListDto>(count, ObjectMapper.Map<List<LaunchListDto>>(launches));
        }

        public async Task<GetLaunchForEditOutput> GetLaunchForEdit(NullableIdDto input)
        {
            LaunchEditDto launchEditDto;

            if (input.Id.HasValue)
            {
                var launch = await _launchRepository.GetAsync(input.Id.Value);
                launchEditDto = ObjectMapper.Map<LaunchEditDto>(launch);
            }
            else
            {
                launchEditDto = new LaunchEditDto();
            }

            return new GetLaunchForEditOutput
            {
                Launch = launchEditDto,
                Stages = GetStagesForCombobox()
            };
        }

        public async Task CreateOrUpdateLaunch(LaunchEditDto input)
        {
            if (input.Id.HasValue)
                await UpdateBatchAsync(input);
            else
                await CreateBatchAsync(input);
        }

        public async Task DeleteLaunch(EntityDto input)
        {
            await _launchRepository.DeleteAsync(input.Id);
        }

        private async Task CreateBatchAsync(LaunchEditDto input)
        {
            var launch = new Launch(input.ModelId, input.Code, input.Name, input.Description, input.Stage)
            {
          
                PlannedFinishDate = input.PlannedFinishDate,
                CompletionPriority = input.CompletionPriority
            };
            await _launchRepository.InsertAsync(launch);
        }

        private async Task UpdateBatchAsync(LaunchEditDto input)
        {
            Debug.Assert(input.Id != null, "input.Id != null");
            var launch = await _launchRepository.GetAsync(input.Id.Value);
            ObjectMapper.Map(input, launch);
            await _launchRepository.UpdateAsync(launch);
        }

        private static ICollection<ComboboxItemDto> GetStagesForCombobox()
        {
            var list = new List<ComboboxItemDto>();
            foreach (int value in Enum.GetValues(typeof(DevelopmentStage)))
                list.Add(new ComboboxItemDto(value.ToString(), Enum.GetName(typeof(DevelopmentStage), value)));
            return list;
        }

        #endregion
    }
}